package com.imooc.course.business.controller.album;

import com.alibaba.fastjson.JSON;
import com.imooc.course.business.form.MemberForm;
import com.imooc.course.business.form.ShortMessagingServiceForm;
import com.imooc.course.server.dto.LoginMemberDto;
import com.imooc.course.server.dto.MemberDto;
import com.imooc.course.server.dto.ResponseDto;
import com.imooc.course.server.dto.ShortMessagingServiceDto;
import com.imooc.course.server.enums.SmsUseEnum;
import com.imooc.course.server.service.MemberService;
import com.imooc.course.server.service.impl.ShortMessagingServiceServiceImpl;
import com.imooc.course.server.utils.CopyUtil;
import com.imooc.course.server.utils.UuidUtil;
import com.imooc.course.server.utils.ValidatorUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/album/member")
public class AlbumMemberController {

    private static final Logger log = LoggerFactory.getLogger(AlbumMemberController.class);
    public static final String BUSINESS_NAME = "会员";

    @Resource(name = "memberService")
    private MemberService memberService;

    @Resource(name = "shortMessagingServiceService")
    private ShortMessagingServiceServiceImpl shortMessagingServiceService;

    @Resource
    public RedisTemplate redisTemplate;


    @PostMapping("/register")
    public ResponseDto addUser(@RequestBody MemberForm memberForm) {
        //入参检查
        ValidatorUtil.notNull(memberForm.getMobile(), "手机号");
        ValidatorUtil.minimumToMaximum(memberForm.getMobile(), "手机号", 11, 11);
        ValidatorUtil.minimumToMaximum(memberForm.getName(), "昵称", 1, 50);
        ValidatorUtil.notNull(memberForm.getPassword(), "密码");

        //短信验证------------------------------------
        ShortMessagingServiceForm smsForm = new ShortMessagingServiceForm();
        smsForm.setMobile(memberForm.getMobile());
        smsForm.setCode(memberForm.getSmsCode());
        smsForm.setUse(SmsUseEnum.REGISTER.getCode());

        ShortMessagingServiceDto smsDto = CopyUtil.copy(smsForm, ShortMessagingServiceDto.class);
        shortMessagingServiceService.validateShortMessage(smsDto);

        //保存至数据库-------------------------------
        MemberDto memberDto = CopyUtil.copy(memberForm, MemberDto.class);

        memberDto.setPassword(DigestUtils.md5DigestAsHex(memberDto.getPassword().getBytes()));
        memberService.save(memberDto);
        return ResponseDto.success();
    }

    /**
     * 会员登录
     * @param memberForm
     * @return
     */
    @PostMapping("/login")
    public ResponseDto login(@RequestBody MemberForm memberForm) {

        String kaptcha = (String)redisTemplate.opsForValue().get(memberForm.getImageCodeToken());
        if (StringUtils.isEmpty(kaptcha)) {
            log.info("用户登录失败，验证码已过期 kaptcha = {}", kaptcha);
            redisTemplate.delete(memberForm.getImageCodeToken());
            return ResponseDto.fail().setMsg("验证码已过期");
        }
        if (!memberForm.getImageCode().trim().toLowerCase().equals(kaptcha.toLowerCase())) {
            log.info("用户登录失败，验证码错误 用户输入 = {}，kaptcha = {}", memberForm.getImageCode().trim().toLowerCase(), kaptcha);
            redisTemplate.delete(memberForm.getImageCodeToken());
            return ResponseDto.fail().setMsg("验证码错误");
        }

        redisTemplate.delete(memberForm.getImageCodeToken());

        MemberDto memberDto = CopyUtil.copy(memberForm, MemberDto.class);
        log.info("发送登录请求前的 password 第一次加密 = {}",memberForm.getPassword());
        //前端登录时会将密码加密一次，后端收到后再加密一次。
        /**
         * MD5实际上是不能解的，
         * 凡是宣称能解MD5的，其实都是提前将常见的密码组合计算为16进制MD5字符值后，
         * 将计算出来的MD5值为KEY，密码为value，存进数据库。
         * 当你要使用他的解密服务时，就是在它的数据库中查询。
         * 其本质是肓猜。
         * 只要在用户的密码前面或后面或前后都加上一串保密不暴露的盐值(开发者定义的随机字符串)再生成MD5值，
         * 就难以被破解，即使破解后得到的也是密码和随机字符串的组合值，并没有得到用户的真实密码。
         * 最后，用户创建时，密码传到后端也会再被加密一次，
         * 这样，无论是后端密码泄露还是前端密码泄露，别人也无法得到真正的用户密码。
         * @type {string}
         */
        memberDto.setPassword(DigestUtils.md5DigestAsHex(memberDto.getPassword().getBytes()));
        log.info("后端收到 password 第二次加密 = {}",memberDto.getPassword());

        LoginMemberDto loginMemberDto = memberService.login(memberDto);
        loginMemberDto.setToken(UuidUtil.getShortUuid());

        //实现单点登录：后端接口验证用户登录成功向前端返回用户信息时带上一个token标记，
        //后端用户的所有操作都会在请求头加上这个token标记，后端用这个验证是否为同一个用户。
        redisTemplate.opsForValue().set(loginMemberDto.getToken(), JSON.toJSONString(loginMemberDto), 3600, TimeUnit.SECONDS);

        return ResponseDto.success().setContent(loginMemberDto);
    }

    /**
     * 退出登录
     * @param token
     * @return
     */
    @GetMapping("/logout/{token}")
    public ResponseDto logout(@PathVariable String token) {

        redisTemplate.delete(token);

        return ResponseDto.success();
    }

    /**
     * 检查手机号是否已经注册
     * @param mobile
     * @return
     */
    @PostMapping("/check-mobile")
    public ResponseDto checkMobile(String mobile) {
        MemberDto memberDto = memberService.matchingMobile(mobile);
        if (memberDto == null) {
            return ResponseDto.fail();
        } else {
            return ResponseDto.success();
        }
    }

    /**
     * 重置密码
     * @param memberForm
     * @return
     */
    @PostMapping("/reset-password")
    public ResponseDto resetPassword(@RequestBody MemberForm memberForm) {
        //入参检查
        ValidatorUtil.notNull(memberForm.getMobile(), "手机号");
        ValidatorUtil.minimumToMaximum(memberForm.getMobile(), "手机号", 11, 11);
        ValidatorUtil.notNull(memberForm.getPassword(), "密码");

        //短信验证------------------------------------
        ShortMessagingServiceForm smsForm = new ShortMessagingServiceForm();
        smsForm.setMobile(memberForm.getMobile());
        smsForm.setCode(memberForm.getSmsCode());
        smsForm.setUse(SmsUseEnum.FORGET.getCode());

        ShortMessagingServiceDto smsDto = CopyUtil.copy(smsForm, ShortMessagingServiceDto.class);
        shortMessagingServiceService.validateShortMessage(smsDto);

        //保存至数据库-------------------------------
        MemberDto memberDto = CopyUtil.copy(memberForm, MemberDto.class);

        memberDto.setPassword(DigestUtils.md5DigestAsHex(memberDto.getPassword().getBytes()));
        memberService.restPassword(memberDto);
        return ResponseDto.success();
    }
}
